/**
 * @file	multi.c
 * @author	chipsea
 * @brief	This file contains function that allows user setup tasks
 * @version	0.1
 * @date	2020-11-30
 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd.
 * @note
 */

/*********************************************************************
* INCLUDES
*/
#include <string.h>
#include "bcomdef.h"
#include "OSAL.h"
#include "hci_tl.h"
#include "ll_common.h"
#include "l2cap.h"
#include "gap.h"
#include "linkdb.h"
#include "att.h"
#include "gatt.h"
#include "osal_snv.h"
#include "gapbondmgr.h"

/* This Header file contains all BLE API and icall structure definition */


#include "multi.h"
#include "multi_role.h"
#include "log.h"
#include "bleuart_service.h"


/*********************************************************************
* MACROS
*/

/*********************************************************************
* CONSTANTS
*/
// Profile Events
// Profile Events
//#define START_ADVERTISING_EVT         0x0001  // Start Advertising
//#define RSSI_READ_EVT                 0x0002  // Read RSSI
//#define START_CONN_UPDATE_EVT         0x0004  // Start Connection Update Procedure
//#define CONN_PARAM_TIMEOUT_EVT        0x0008  // Connection Parameters Update Timeout
//#define MULTI_CONN_PERIOD_EVT       0x0010  // multi conn

//#define GAPROLE_ALL_EVENTS            (GAPROLE_ICALL_EVT     | \
//                                       START_ADVERTISING_EVT | \
//                                       CONN_PARAM_TIMEOUT_EVT)

#define DEFAULT_ADVERT_OFF_TIME       30000   // 30 seconds

// connection interval
#define DEFAULT_MIN_CONN_INTERVAL     0x0006  // 100 milliseconds
#define DEFAULT_MAX_CONN_INTERVAL     0x0C80  // 4 seconds
#define MIN_CONN_INTERVAL             0x0006  // minimum connection interval
#define MAX_CONN_INTERVAL             0x0C80  // max connection interval

#define MIN_SLAVE_LATENCY             0       // min slave latency
#define MAX_SLAVE_LATENCY             500     // max slave latency

// supervision timeout
#define MIN_TIMEOUT_MULTIPLIER        0x000a  // min supervision timeout
#define MAX_TIMEOUT_MULTIPLIER        0x0c80  // max supervision timeout
#define DEFAULT_TIMEOUT_MULTIPLIER    1000    // 10 seconds

// Task configuration
#define GAPROLE_TASK_PRIORITY         3
#ifndef GAPROLE_TASK_STACK_SIZE
#define GAPROLE_TASK_STACK_SIZE       540
#endif

/*********************************************************************
* TYPEDEFS
*/

// App event structure
typedef struct
{
	uint8_t  event;  // event type
	uint8_t  status; // event status
} gapRoleEvt_t;

// set/get param event structure
typedef struct
{
	uint16_t  connHandle;  //connection handle
	uint16_t  value;       //value
} gapRoleInfoParam_t;

/*********************************************************************
* GLOBAL VARIABLES
*/

// Link DB maximum number of connections
//#ifndef STACK_LIBRARY
uint8_t linkDBNumConns = MAX_NUM_LL_CONN;      // hardcoded, TI read this value from linkDB
//#else /* ! STACK_LIBRARY */
//extern uint8_t linkDBNumConns;
//#endif /* STACK_LIBRARY */

/*********************************************************************
* EXTERNAL VARIABLES
*/

/*********************************************************************
* EXTERNAL FUNCTIONS
*/
extern uint8_t LL_GetLinkRole(uint8_t connId);

/*********************************************************************
* LOCAL VARIABLES
*/
//static uint8 gapRole_TaskID;   // Task ID for internal task/event processing
uint8 gapRole_TaskID;

//static gaprole_AdvState_t gapRole_AdvState;
static gaprole_ScanState_t gapRole_ScanState;
static gaprole_ConnnectState_t gapRole_ConnectState[MAX_NUM_LL_CONN];

/*********************************************************************
* Profile Parameters - reference GAPROLE_PROFILE_PARAMETERS for
* descriptions
*/
static uint8_t  gapRole_profileRole;
static uint8_t  gapRole_IRK[KEYLEN];
static uint8_t  gapRole_SRK[KEYLEN];
static uint32_t gapRole_signCounter;
static uint8_t  gapRole_bdAddr[B_ADDR_LEN];
static uint8_t  gapRole_AdvEnabled = FALSE;
static uint8_t  gapRole_AdvNonConnEnabled = FALSE;
static uint16_t gapRole_AdvertOffTime = DEFAULT_ADVERT_OFF_TIME;
static uint8_t  gapRole_AdvertDataLen = 3;

static uint8_t  gapRole_AdvertData[B_MAX_ADV_LEN] =
{
	0x02,   // length of this data
	GAP_ADTYPE_FLAGS,   // AD Type = Flags
	// Limited Discoverable & BR/EDR not supported
	(GAP_ADTYPE_FLAGS_GENERAL | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED),
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};

// Connection parameter update parameters.
static gapRole_updateConnParams_t gapRole_updateConnParams =
{
	.paramUpdateEnable = GAPROLE_LINK_PARAM_UPDATE_APP_DECIDES,
	.connHandle = INVALID_CONNHANDLE,
	.minConnInterval = DEFAULT_MIN_CONN_INTERVAL,
	.maxConnInterval = DEFAULT_MAX_CONN_INTERVAL,
	.slaveLatency = MIN_SLAVE_LATENCY,
	.timeoutMultiplier = DEFAULT_TIMEOUT_MULTIPLIER
};

static uint8_t paramUpdateNoSuccessOption = GAPROLE_NO_ACTION;

static uint8_t  gapRole_ScanRspDataLen = 0;
static uint8_t  gapRole_ScanRspData[B_MAX_ADV_LEN] = {0};
static uint8_t  gapRole_AdvEventType;
static uint8_t  gapRole_AdvDirectType;
static uint8_t  gapRole_AdvDirectAddr[B_ADDR_LEN] = {0};
static uint8_t  gapRole_AdvChanMap;
static uint8_t  gapRole_AdvFilterPolicy;

static uint8_t  gapRoleMaxScanRes = 8;

// Application callbacks
static gapMultiRolesCBs_t *pGapRoles_AppCGs = NULL;

// Multi Role list
uint8 multi_updateParamList[MAX_NUM_LL_CONN]= {0};
/*********************************************************************
* Profile Attributes - variables
*/

/*********************************************************************
* Profile Attributes - Table
*/

/*********************************************************************
* LOCAL FUNCTIONS
*/
//static void gapRole_init(void);
//static void gapRole_taskFxn(UArg a0, UArg a1);
//static uint8_t gapRole_processStackMsg(ICall_Hdr *pMsg);
static void gapRole_ProcessOSALMsg(osal_event_hdr_t *pMsg);
static uint8_t gapRole_processGAPMsg(gapEventHdr_t *pMsg);
static void gapRole_SetupGAP(uint8_t *numConns);
//static void gapRole_setEvent(uint32_t event);
static void gapRole_HandleParamUpdateNoSuccess(void);

static void MultiRole_startConnUpdate(uint8 handleFailure);

/*********************************************************************
* CALLBACKS
*/
//void gapRole_clockHandler(UArg a0);

/*********************************************************************
* PUBLIC FUNCTIONS
*/

/*********************************************************************
* @brief   Set a GAP Role parameter.
*
* Public function defined in peripheral.h.
*/
bStatus_t GAPMultiRole_SetParameter(uint16_t param, uint8_t len, void *pValue, uint8_t connHandle)
{
	bStatus_t ret = SUCCESS;

	switch(param)
	{
		case GAPROLE_IRK:
			if(len == KEYLEN)
			{
				VOID osal_memcpy(gapRole_IRK, pValue, KEYLEN);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_SRK:
			if(len == KEYLEN)
			{
				VOID osal_memcpy(gapRole_SRK, pValue, KEYLEN);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_SIGNCOUNTER:
			if(len == sizeof(uint32_t))
			{
				gapRole_signCounter = *((uint32_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

        case GAPROLE_BD_ADDR:
			if(len == B_ADDR_LEN)
			{
				extern uint8 ownPublicAddr[ LL_DEVICE_ADDR_LEN ];
                VOID osal_memcpy( gapRole_bdAddr, pValue, B_ADDR_LEN ) ;
                VOID osal_memcpy( ownPublicAddr, pValue, B_ADDR_LEN ) ;
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADVERT_ENABLED:  //connectable advertising
			if(len == sizeof(uint8_t))
			{
				// Non-connectable advertising must be disabled.
				if(gapRole_AdvNonConnEnabled != TRUE)
				{
					uint8_t oldAdvEnabled = gapRole_AdvEnabled;
					gapRole_AdvEnabled = *((uint8_t *)pValue);

//		printf("oldAdvEnabled %d,gapRole_AdvEnabled %d \n",oldAdvEnabled,gapRole_AdvEnabled);
					// If ending advertising
					if((oldAdvEnabled) && (gapRole_AdvEnabled == FALSE))
					{
						// Cancel advertising
						return GAP_EndDiscoverable(gapRole_TaskID);
					}
					// Of starting advertising
					else if((oldAdvEnabled == FALSE) && (gapRole_AdvEnabled))
					{
//          printf("linkDB_NumActive() %d\n",linkDB_NumActive());
						// Turn on advertising.
						if(linkDB_NumActive() >= linkDBNumConns)  // Don't do conn adv if we don't have any available links
						{
							gapRole_AdvEnabled = FALSE;
							return bleNoResources; // no more available links
						}
						else
						{
							gapRole_setEvent(START_ADVERTISING_EVT);
						}
					}
				}
				else
				{
					ret = bleIncorrectMode;
				}
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADV_NONCONN_ENABLED:
			if(len == sizeof(uint8_t))
			{
				// Connectable advertising must be disabled.
				if(gapRole_AdvEnabled != TRUE)
				{
					uint8_t oldAdvEnabled = gapRole_AdvNonConnEnabled;
					gapRole_AdvNonConnEnabled = *((uint8_t *)pValue);

					// If cancelling advertising
					if((oldAdvEnabled) && (gapRole_AdvNonConnEnabled == FALSE))
					{
						// End advertising
						VOID GAP_EndDiscoverable(gapRole_TaskID);
					}
					// If starting advertising
					else if((oldAdvEnabled == FALSE) && (gapRole_AdvNonConnEnabled))
					{
						// Turn on advertising
						gapRole_setEvent(START_ADVERTISING_EVT);
					}
				}
				else
				{
					ret = bleIncorrectMode;
				}
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADVERT_OFF_TIME:
			if(len == sizeof(uint16_t))
			{
				gapRole_AdvertOffTime = *((uint16_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADVERT_DATA:
			if(len <= B_MAX_ADV_LEN)
			{
				VOID osal_memset(gapRole_AdvertData, 0, B_MAX_ADV_LEN);
				VOID osal_memcpy(gapRole_AdvertData, pValue, len);
				gapRole_AdvertDataLen = len;

				// Update the advertising data
				ret = GAP_UpdateAdvertisingData(gapRole_TaskID,
				                                TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_SCAN_RSP_DATA:
			if(len <= B_MAX_ADV_LEN)
			{
				VOID osal_memset(gapRole_ScanRspData, 0, B_MAX_ADV_LEN);
				VOID osal_memcpy(gapRole_ScanRspData, pValue, len);
				gapRole_ScanRspDataLen = len;

				// Update the Response Data
				ret = GAP_UpdateAdvertisingData(gapRole_TaskID,
				                                FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADV_EVENT_TYPE:
			if((len == sizeof(uint8_t)) && (*((uint8_t *)pValue) <= GAP_ADTYPE_ADV_LDC_DIRECT_IND))
			{
				gapRole_AdvEventType = *((uint8_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADV_DIRECT_TYPE:
			if((len == sizeof(uint8_t)) && (*((uint8_t *)pValue) <= ADDRTYPE_PRIVATE_RESOLVE))
			{
				gapRole_AdvDirectType = *((uint8_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADV_DIRECT_ADDR:
			if(len == B_ADDR_LEN)
			{
				VOID osal_memcpy(gapRole_AdvDirectAddr, pValue, B_ADDR_LEN);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;
        
		case GAPROLE_ADV_CHANNEL_MAP:
			if((len == sizeof(uint8_t)) && (*((uint8_t *)pValue) <= 0x07))
			{
				gapRole_AdvChanMap = *((uint8_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_ADV_FILTER_POLICY:
			if((len == sizeof(uint8_t)) && (*((uint8_t *)pValue) <= GAP_FILTER_POLICY_WHITE))
			{
				gapRole_AdvFilterPolicy = *((uint8_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_PARAM_UPDATE_ENABLE:
			if((len == sizeof(uint8)) && (*((uint8*)pValue) <= TRUE))
			{
				gapRole_updateConnParams.paramUpdateEnable = *((uint8*)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		case GAPROLE_MIN_CONN_INTERVAL:
		{
			uint16 newInterval = *((uint16*)pValue);

			if(len == sizeof(uint16)           &&
			   (newInterval >= MIN_CONN_INTERVAL) &&
			   (newInterval <= MAX_CONN_INTERVAL))
			{
				gapRole_updateConnParams.minConnInterval = newInterval;
			}
			else
			{
				ret = bleInvalidRange;
			}
		}
		break;

		case GAPROLE_MAX_CONN_INTERVAL:
		{
			uint16 newInterval = *((uint16*)pValue);

			if(len == sizeof(uint16)          &&
			   (newInterval >= MIN_CONN_INTERVAL) &&
			   (newInterval <= MAX_CONN_INTERVAL))
			{
				gapRole_updateConnParams.maxConnInterval = newInterval;
			}
			else
			{
				ret = bleInvalidRange;
			}
		}
		break;

		case GAPROLE_SLAVE_LATENCY:
		{
			uint16 latency = *((uint16*)pValue);

			if(len == sizeof(uint16) && (latency < MAX_SLAVE_LATENCY))
			{
				gapRole_updateConnParams.slaveLatency = latency;
			}
			else
			{
				ret = bleInvalidRange;
			}
		}
		break;

		case GAPROLE_TIMEOUT_MULTIPLIER:
		{
			uint16 newTimeout = *((uint16*)pValue);

			if(len == sizeof(uint16)
			   && (newTimeout >= MIN_TIMEOUT_MULTIPLIER) && (newTimeout <= MAX_TIMEOUT_MULTIPLIER))
			{
				gapRole_updateConnParams.timeoutMultiplier = newTimeout;
			}
			else
			{
				ret = bleInvalidRange;
			}
		}
		break;

		case GAPROLE_MAX_SCAN_RES:
			if(len == sizeof(uint8_t))
			{
				gapRoleMaxScanRes = *((uint8_t *)pValue);
			}
			else
			{
				ret = bleInvalidRange;
			}

			break;

		default:

			// The param value isn't part of this profile, try the GAP.
			if((param < TGAP_PARAMID_MAX) && (len == sizeof(uint16_t)))
			{
				ret = GAP_SetParamValue(param, *((uint16_t *)pValue));
			}
			else
			{
				ret = INVALIDPARAMETER;
			}

			break;
	}

	return (ret);
}

/*********************************************************************
* @brief   Get a GAP Role parameter.
*
* Public function defined in peripheral.h.
*/
bStatus_t GAPMultiRole_GetParameter(uint16_t param, void *pValue, uint8_t connHandle)
{
	bStatus_t ret = SUCCESS;

	switch(param)
	{
		case GAPROLE_PROFILEROLE:
			*((uint8_t *)pValue) = gapRole_profileRole;
			break;

		case GAPROLE_IRK:
			VOID osal_memcpy(pValue, gapRole_IRK, KEYLEN);
			break;

		case GAPROLE_SRK:
			VOID osal_memcpy(pValue, gapRole_SRK, KEYLEN);
			break;

		case GAPROLE_SIGNCOUNTER:
			*((uint32_t *)pValue) = gapRole_signCounter;
			break;

		case GAPROLE_BD_ADDR:
			VOID osal_memcpy(pValue, gapRole_bdAddr, B_ADDR_LEN);
			break;

		case GAPROLE_ADVERT_ENABLED:
			*((uint8_t *)pValue) = gapRole_AdvEnabled;
			break;

		case GAPROLE_ADV_NONCONN_ENABLED:
			*((uint8_t *)pValue) = gapRole_AdvNonConnEnabled;
			break;

		case GAPROLE_ADVERT_OFF_TIME:
			*((uint16_t *)pValue) = gapRole_AdvertOffTime;
			break;

		case GAPROLE_ADVERT_DATA:
			VOID osal_memcpy(pValue, gapRole_AdvertData, gapRole_AdvertDataLen);
			break;

		case GAPROLE_SCAN_RSP_DATA:
			VOID osal_memcpy(pValue, gapRole_ScanRspData, gapRole_ScanRspDataLen);
			break;

		case GAPROLE_ADV_EVENT_TYPE:
			*((uint8_t *)pValue) = gapRole_AdvEventType;
			break;

		case GAPROLE_ADV_DIRECT_TYPE:
			*((uint8_t *)pValue) = gapRole_AdvDirectType;
			break;

		case GAPROLE_ADV_DIRECT_ADDR:
			VOID osal_memcpy(pValue, gapRole_AdvDirectAddr, B_ADDR_LEN);
			break;

		case GAPROLE_ADV_CHANNEL_MAP:
			*((uint8_t *)pValue) = gapRole_AdvChanMap;
			break;

		case GAPROLE_ADV_FILTER_POLICY:
			*((uint8_t *)pValue) = gapRole_AdvFilterPolicy;
			break;

		case GAPROLE_PARAM_UPDATE_ENABLE:
			*((uint16*)pValue) = gapRole_updateConnParams.paramUpdateEnable;
			break;

		case GAPROLE_MIN_CONN_INTERVAL:
			*((uint16*)pValue) = gapRole_updateConnParams.minConnInterval;
			break;

		case GAPROLE_MAX_CONN_INTERVAL:
			*((uint16*)pValue) = gapRole_updateConnParams.maxConnInterval;
			break;

		case GAPROLE_SLAVE_LATENCY:
			*((uint16*)pValue) = gapRole_updateConnParams.slaveLatency;
			break;

		case GAPROLE_TIMEOUT_MULTIPLIER:
			*((uint16*)pValue) = gapRole_updateConnParams.timeoutMultiplier;
			break;

		case GAPROLE_MAX_SCAN_RES:
			*((uint8_t *)pValue) = gapRoleMaxScanRes;
			break;

		case GAPROLE_SCAN_STATE:
			*((uint8_t *)pValue) = gapRole_ScanState;
			break;

		case GAPROLE_CONNECTION_STATE:
			if(connHandle < MAX_NUM_LL_CONN)
			{
				*((uint8_t *)pValue) = gapRole_ConnectState[connHandle];
			}
			else
			{
				*((uint8_t *)pValue) = GAPROLE_ERROR_STATE;
			}

			break;

		default:

			// The param value isn't part of this profile, try the GAP.
			if(param < TGAP_PARAMID_MAX)
			{
				*((uint16_t *)pValue) = GAP_GetParamValue(param);
			}
			else
			{
				ret = INVALIDPARAMETER;
			}

			break;
	}

	return (ret);
}

/*********************************************************************
* @brief   Does the device initialization.
*
* Public function defined in peripheral.h.
*/
bStatus_t GAPMultiRole_StartDevice(gapMultiRolesCBs_t *pAppCallbacks, uint8_t * numConns)
{
	// Clear all of the Application callbacks
	if(pAppCallbacks)
	{
		pGapRoles_AppCGs = pAppCallbacks;
	}

	// Start the GAP
	gapRole_SetupGAP(numConns);

// ========= from central.c, profile could not be set as central + peripheral. walkaround?
//  return GAP_DeviceInit( gapCentralRoleTaskId, GAP_PROFILE_CENTRAL,
//                         gapCentralRoleMaxScanRes, gapCentralRoleIRK,
//                         gapCentralRoleSRK, &gapCentralRoleSignCounter );

	return (SUCCESS);
}

/*********************************************************************
* @brief   Terminates the existing connection.
*
* Public function defined in peripheral.h.
*/
bStatus_t GAPMultiRole_TerminateConnection(uint16_t connHandle)
{
	return (GAP_TerminateLinkReq(gapRole_TaskID, connHandle,
	                             HCI_DISCONNECT_REMOTE_USER_TERM));
}



/*********************************************************************
* LOCAL FUNCTION PROTOTYPES
*/

/*********************************************************************
* @fn      gapRole_init
*
* @brief   Initialization function for the GAP Role Task.
*
* @param   none
*
* @return  none
*/
void GAPMultiRole_Init(uint8 taskId)
{
	uint8_t i;
	gapRole_TaskID = taskId;
//	gapRole_AdvState = GAPROLE_ADV_OFF_STATE;
	gapRole_ScanState = GAPROLE_SCAN_OFF_STATE;

	for(i=0; i<MAX_NUM_LL_CONN; i++)//让所有设备在初始状态
	{
		gapRole_ConnectState[i] = GAPROLE_IDLE_STATE;
	}

//    gapRole_ConnectionHandle = INVALID_CONNHANDLE;    // peripheral.c , do we need it???

	// Initialize the Profile Advertising and Connection Parameters
	gapRole_profileRole = GAP_PROFILE_PERIPHERAL | GAP_PROFILE_CENTRAL;//设置设备角色，即可以发起广播，又可以扫描并发起连接

	VOID osal_memset(gapRole_IRK, 0, KEYLEN);//清空密钥
	VOID osal_memset(gapRole_SRK, 0, KEYLEN);
	gapRole_signCounter = 0;

	gapRole_AdvEventType = GAP_ADTYPE_ADV_IND;//设置广播类型  不定向广播
	gapRole_AdvDirectType = ADDRTYPE_PUBLIC;
	gapRole_AdvChanMap = GAP_ADVCHAN_ALL;//广播信道
	gapRole_AdvFilterPolicy = GAP_FILTER_POLICY_ALL;//扫描过滤策略

	GAP_RegisterForHCIMsgs(taskId);
}

/**
* @brief   Establish a link to a peer device.
*
* Public function defined in central.h.
*/
bStatus_t GAPMultiRole_EstablishLink(uint8_t highDutyCycle, uint8_t whiteList,
                                     uint8_t addrTypePeer, uint8_t *peerAddr)
{
	gapEstLinkReq_t params;

	params.taskID = gapRole_TaskID;
	params.highDutyCycle = highDutyCycle;
	params.whiteList = whiteList;
	params.addrTypePeer = addrTypePeer;
	VOID osal_memcpy(params.peerAddr, peerAddr, B_ADDR_LEN);

	return GAP_EstablishLinkReq(&params);
}

/**
* @brief   Start a device discovery scan.
*
* Public function defined in central.h.
*/
bStatus_t GAPMultiRole_StartDiscovery(uint8_t mode, uint8_t activeScan, uint8_t whiteList)
{
	gapDevDiscReq_t params;

	params.taskID = gapRole_TaskID;
	params.mode = mode;
	params.activeScan = activeScan;
	params.whiteList = whiteList;

	gapRole_ScanState = GAPROLE_SCAN_ON_STATE;

	return GAP_DeviceDiscoveryRequest(&params);
}

/**
* @brief   Cancel a device discovery scan.
*
* Public function defined in central.h.
*/
bStatus_t GAPMultiRole_CancelDiscovery(void)
{
	gapRole_ScanState = GAPROLE_SCAN_OFF_STATE;
	return GAP_DeviceDiscoveryCancel(gapRole_TaskID);
}

///*********************************************************************
//* @fn      gapRole_taskFxn
//*
//* @brief   Task entry point for the GAP Peripheral Role.
//*
//* @param   a0 - first argument
//* @param   a1 - second argument
//*
//* @return  none
//*/
//static void gapRole_taskFxn(UArg a0, UArg a1)
uint16 GAPMultiRole_ProcessEvent(uint8 task_id, uint16 events)
{

//	LOG("GAPMultiRole_ProcessEvent \n");
	if(events & SYS_EVENT_MSG)
	{
		uint8 *pMsg;

		if((pMsg = osal_msg_receive(gapRole_TaskID)) != NULL)
		{
			gapRole_ProcessOSALMsg((osal_event_hdr_t *)pMsg);

			// Release the OSAL message
			VOID osal_msg_deallocate(pMsg);
		}

		// return unprocessed events
		return (events ^ SYS_EVENT_MSG);
	}

	if(events & START_ADVERTISING_EVT)
	{
		LOG("START_ADVERTISING_EVT \n");

		// If any type of advertising is enabled
		if(gapRole_AdvEnabled || gapRole_AdvNonConnEnabled)
		{
			gapAdvertisingParams_t params;

			// Setup advertisement parameters
			if(gapRole_AdvNonConnEnabled)
			{
				// Only advertise non-connectable undirected.
				params.eventType = GAP_ADTYPE_ADV_NONCONN_IND;
			}
			else
			{
				// Connectable advertising
				params.eventType = gapRole_AdvEventType;
				params.initiatorAddrType = gapRole_AdvDirectType;
				VOID osal_memcpy(params.initiatorAddr, gapRole_AdvDirectAddr, B_ADDR_LEN);
			}

			// Set advertising channel map
			params.channelMap = gapRole_AdvChanMap;

			// Set advertising filter policy
			params.filterPolicy = gapRole_AdvFilterPolicy;

			// Start advertising
			uint8 ret = GAP_MakeDiscoverable(gapRole_TaskID, &params);
			LOG("GAP_MakeDiscoverable Ret = 0x%02X\n", ret);
		}

		return (events ^ START_ADVERTISING_EVT);
	}

	if(events & CONN_PARAM_TIMEOUT_EVT)
	{
		// Unsuccessful in updating connection parameters
		gapRole_HandleParamUpdateNoSuccess();
		return (events ^ CONN_PARAM_TIMEOUT_EVT);
	}

	if(events & START_CONN_UPDATE_EVT)
	{
		MultiRole_startConnUpdate(GAPROLE_NO_ACTION);
		return (events ^ START_CONN_UPDATE_EVT);
	}

	// Discard unknown events
	return 0;
}

///*********************************************************************
//* @fn      gapRole_processStackMsg
//*
//* @brief   Process an incoming task message.
//*
//* @param   pMsg - message to process
//*
//* @return  none
//*/
//static uint8_t gapRole_processStackMsg(ICall_Hdr *pMsg)
static void gapRole_ProcessOSALMsg(osal_event_hdr_t *pMsg)
{
//  uint8_t safeToDealloc = TRUE;

	switch(pMsg->event)
	{
		case HCI_GAP_EVENT_EVENT:
			//LOG("GAP EVT[%d]\n", pMsg->status);
			if(pMsg->status==HCI_LE_EVENT_CODE)
			{
				hciEvt_BLEEvent_Hdr_t *pPkt = (hciEvt_BLEEvent_Hdr_t *)pMsg;
				if(pPkt->BLEEventCode == HCI_BLE_READ_REMOTE_FEATURE_COMPLETE_EVENT)
				{
					hciEvt_BLEReadRemoteFeatureComplete_t *pkt = (hciEvt_BLEReadRemoteFeatureComplete_t *)pMsg;
					if(pkt->status == LL_STATUS_SUCCESS)
					{
						LOG("Support feature:%d,%d,%d,%d,%d,%d,%d,%d\n",pkt->features[0],
																		pkt->features[1],
																		pkt->features[2],
																		pkt->features[3],
																		pkt->features[4],
																		pkt->features[5],
																		pkt->features[6],
																		pkt->features[7]);
					}
				}
				else if ( pPkt->BLEEventCode == HCI_BLE_DATA_LENGTH_CHANGE_EVENT )
				{
                    hciEvt_BLEDataLenChange_t * pkt = (hciEvt_BLEDataLenChange_t *)pMsg;
                    LOG("[HCI DLE EVT]%d, %d %d %d %d\n",pkt->connHandle, pkt->MaxRxOctets,pkt->MaxRxTime,
                                                    pkt->MaxTxOctets,pkt->MaxTxTime);
                    
                    uint8 index = findConnectIndexByConnectionHandle(LL_ROLE_MASTER, pkt->connHandle);
                    if(index < g_slaveMaxNum)
                    {
						if(deviceFeatureSet.featureSet[1] & LL_FEATURE_2M_PHY)
						{
							linkInitParam[index].link_status = LINK_STATUS_SET_PHYMODE;
							linkInitParam[index].link_cmd = 1;
							ble_task_set(USER_TASK_START, START_LINK_STATUS_EVT, NULL);
						}
						else
						{
							linkInitParam[index].link_status = LINK_STATUS_EXCHANGE_MTU;
							linkInitParam[index].link_cmd = 1;
							ble_task_set(USER_TASK_START, START_LINK_STATUS_EVT, NULL);
						}
                    }
				}
				else if(pPkt->BLEEventCode == HCI_BLE_PHY_UPDATE_COMPLETE_EVENT )
				{
					hciEvt_BLEPhyUpdateComplete_t * pkt = (hciEvt_BLEPhyUpdateComplete_t *)pMsg;
					if(pkt->status == LL_STATUS_SUCCESS)
					{
						LOG("[HCI PHY EVT]%d, r%d t%d\n",pkt->connHandle, pkt->rxPhy,pkt->txPhy);
					}
                    
                    uint8 index = findConnectIndexByConnectionHandle(LL_ROLE_MASTER, pkt->connHandle);
                    if(index < g_slaveMaxNum)
                    {
                        linkInitParam[index].link_status = LINK_STATUS_EXCHANGE_MTU;
						linkInitParam[index].link_cmd = 1;
						ble_task_set(USER_TASK_START, START_LINK_STATUS_EVT, NULL);
                    }
				}
			}
			else if(pMsg->status==HCI_READ_REMOTE_INFO_COMPLETE_EVENT_CODE)
			{
				hciEvt_BLEReadRemoteVersionComplete_t *pPkt = (hciEvt_BLEReadRemoteVersionComplete_t *)pMsg;
				LOG("[HCI VERSION EVT]%d, %d,%d\n",pPkt->connHandle, pPkt->status,pPkt->connHandle);
				if(pPkt->status == LL_STATUS_SUCCESS)
				{
					LOG("verNum=%x,comId=%x,subVer=%x\n",pPkt->verNum, pPkt->comId, pPkt->subverNum);
					uint8 index = findConnectIndexByConnectionHandle(LL_ROLE_MASTER, pPkt->connHandle);
                    if(index < g_slaveMaxNum)
					{
						if(pPkt->comId == 0x06A7) //LL_COMPANY_ID   0x06A7    // Chipsea
						{
							linkInitParam[index].link_status = LINK_STATUS_SET_DATALEN;
						}
						else
						{
							if(slave_handle[index].ccc)
							{
								linkInitParam[index].link_status = LINK_STATUS_ENABLE_NOTIFY;
							}
							else
							{
								linkInitParam[index].link_status = LINK_STATUS_DISCOVER_SERVICE_BY_UUID;
							}
						}
						linkInitParam[index].link_cmd = 1;
						ble_task_set(USER_TASK_START, START_LINK_STATUS_EVT, NULL);
					}
				}
			}
			break;
		case GAP_MSG_EVENT:
			gapRole_processGAPMsg((gapEventHdr_t *)pMsg);
			break;

		case L2CAP_SIGNAL_EVENT:
		{
			l2capSignalEvent_t *pPkt = (l2capSignalEvent_t *)pMsg;

			// Process the Parameter Update Response
			if(pPkt->opcode == L2CAP_PARAM_UPDATE_RSP)
			{
				l2capParamUpdateRsp_t *pRsp = (l2capParamUpdateRsp_t *)&(pPkt->cmd.updateRsp);

				if((pRsp->result == L2CAP_CONN_PARAMS_REJECTED) &&
				   (paramUpdateNoSuccessOption == GAPROLE_TERMINATE_LINK))
				{
					// Cancel connection param update timeout timer
					VOID osal_stop_timerEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT);

					// Terminate connection immediately
					GAPMultiRole_TerminateConnection(pPkt->connHandle);
				}
				else
				{
					uint16_t timeout = GAP_GetParamValue(TGAP_CONN_PARAM_TIMEOUT);

					// Wait for Controller to update connection parameters if they're
					// accepted. Otherwise, decide what to do based on no success option.
					VOID osal_start_timerEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT, timeout);
				}
			}
		}
		break;

		default:
			break;
	}
}

/*********************************************************************
* @fn      gapRole_processGAPMsg
*
* @brief   Process an incoming task message.
*
* @param   pMsg - message to process
*
* @return  none
*/
static uint8_t gapRole_processGAPMsg(gapEventHdr_t *pMsg)
{
//	uint8_t notify = FALSE;   // State changed so notify the app? (default no)

	switch(pMsg->opcode)
	{
		// Device initialized
		case GAP_DEVICE_INIT_DONE_EVENT:
		{
			gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
			bStatus_t stat = pPkt->hdr.status;

			if(stat == SUCCESS)
			{
				// Save off the information
				VOID osal_memcpy(gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN);

				// Update the advertising data
				stat = GAP_UpdateAdvertisingData(gapRole_TaskID,
				                                 TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);
			}

//			notify = TRUE;
		}
		break;

		// Update advertising done
		case GAP_ADV_DATA_UPDATE_DONE_EVENT:
		{
			gapAdvDataUpdateEvent_t *pPkt = (gapAdvDataUpdateEvent_t *)pMsg;

			if(pPkt->hdr.status == SUCCESS)
			{
				// if scan response
				if(pPkt->adType)
				{
					// Setup the Response Data
					pPkt->hdr.status = GAP_UpdateAdvertisingData(gapRole_TaskID,
					                   FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData);
				}
				// if advertisement data and not currently advertising
				else //if (Util_isActive(&startAdvClock) == FALSE)
//          else if ( ( gapRole_state != GAPROLE_ADVERTISING ) &&
//                    ( osal_get_timeoutEx( gapRole_TaskID, START_ADVERTISING_EVT ) == 0 ) )
				{
					// Start advertising
					LOG("Start Advertising Event \n");
					gapRole_setEvent(START_ADVERTISING_EVT);
				}
			}

			// Notify application of failure
//			if(pPkt->hdr.status != SUCCESS)
//			{
//				notify = TRUE;
//			}
		}
		break;

		// Advertising started or ended
		case GAP_MAKE_DISCOVERABLE_DONE_EVENT:
		case GAP_END_DISCOVERABLE_DONE_EVENT:
		{
			gapMakeDiscoverableRspEvent_t *pPkt = (gapMakeDiscoverableRspEvent_t *)pMsg;

			//LOG("Gap Make Or End Discoverable Done Event \n");
			if(pPkt->hdr.status == SUCCESS)
			{
				// If advertising started
				if(pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
				{
					gapRole_AdvEnabled = TRUE;
					LOG("Gap Make Discoverable Done Event \n");
				}
				// If advertising ended
				else
				{
					LOG("Gap End Discoverable Done Event \n");

					if(gapRole_AdvertOffTime != 0)  // Restart advertising if param is set
					{
						if((gapRole_AdvEnabled) || (gapRole_AdvNonConnEnabled))
						{
							LOG("Start OFF adv timer:%d\n", gapRole_AdvertOffTime);
							osal_start_timerEx(gapRole_TaskID, START_ADVERTISING_EVT, gapRole_AdvertOffTime);
						}
					}
					else
					{
						// Since gapRole_AdvertOffTime is set to 0, the device should not
						// automatically become discoverable again after a period of time.
						// Set enabler to FALSE; device will become discoverable again when
						// this value gets set to TRUE
						if(gapRole_AdvEnabled == TRUE)
						{
							gapRole_AdvEnabled = FALSE;
						}
					}
				}

//				notify = TRUE;
			}
			// If we're already advertising
//			else if(pPkt->hdr.status == LL_STATUS_ERROR_COMMAND_DISALLOWED)
//			{
//				notify = FALSE;
//			}
		}
		break;

		// Connection formed
		case GAP_LINK_ESTABLISHED_EVENT:
		{
			gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg;
			uint8_t gapRole = 0;

			// If formed sucessfully
			if(pPkt->hdr.status == SUCCESS)
			{
				if(pPkt->connectionHandle < MAX_NUM_LL_CONN)
				{
					if(LL_GetLinkRole(pPkt->connectionHandle) == LL_ROLE_SLAVE)
					{
						multi_updateParamList[pPkt->connectionHandle] = TRUE;
						gapRole = GAP_PROFILE_PERIPHERAL;
						gapRole_ConnectState[pPkt->connectionHandle] = GAPROLE_SLAVE_CONNECTED_STATE;
					}
					else
					{
						gapRole = GAP_PROFILE_CENTRAL;
						gapRole_ConnectState[pPkt->connectionHandle] = GAPROLE_MASTER_CONNECTED_STATE;
					}
				}

            #if (DEFAULT_GAPBOND_MGR_ENABLE==1)
				// Notify the Bond Manager to the connection
                LOG("GAP_LINK_ESTABLISHED_EVENT\r\n");
				VOID GAPBondMgr_LinkEst(pPkt->devAddrType, pPkt->devAddr,
				                        pPkt->connectionHandle, gapRole);
            #endif
				// Advertising will stop after connection formed as slave
				if(gapRole == GAP_PROFILE_PERIPHERAL)
				{
					gapRole_AdvEnabled = FALSE;
				}
			}

			// If not formed sucessfully
			else if(pPkt->hdr.status == bleGAPConnNotAcceptable)
			{
				// Set enabler to FALSE; device will become discoverable again when
				// this value gets set to TRUE
				gapRole_AdvEnabled = FALSE;

				if(pPkt->connectionHandle < MAX_NUM_LL_CONN)
				{
					gapRole_ConnectState[pPkt->connectionHandle] = GAPROLE_IDLE_STATE;
				}
			}
			else
			{
				if(pPkt->connectionHandle < MAX_NUM_LL_CONN)
				{
					gapRole_ConnectState[pPkt->connectionHandle] = GAPROLE_ERROR_STATE;
				}
			}

//			notify = TRUE;
		}
		break;

		// Connection terminated
		case GAP_LINK_TERMINATED_EVENT:
		{
			gapTerminateLinkEvent_t *pkt = (gapTerminateLinkEvent_t *)pMsg;

			if(pkt->connectionHandle < MAX_NUM_LL_CONN)
			{
				if(pkt->reason == LL_SUPERVISION_TIMEOUT_TERM)
				{
					if(gapRole_ConnectState[pkt->connectionHandle] == GAPROLE_MASTER_CONNECTED_STATE)
					{
						gapRole_ConnectState[pkt->connectionHandle] = GAPROLE_MASTER_DISCONNECTED_AFTER_TIMEOUT_STATE;
					}
					else if(gapRole_ConnectState[pkt->connectionHandle] == GAPROLE_SLAVE_CONNECTED_STATE)
					{
						gapRole_ConnectState[pkt->connectionHandle] = GAPROLE_SLAVE_DISCONNECTED_AFTER_TIMEOUT_STATE;
					}
					else
					{
						gapRole_ConnectState[pkt->connectionHandle] = GAPROLE_IDLE_STATE;
					}

				}
				else
				{
					if(gapRole_ConnectState[pkt->connectionHandle] == GAPROLE_MASTER_CONNECTED_STATE)
					{
						gapRole_ConnectState[pkt->connectionHandle] = GAPROLE_MASTER_DISCONNECTED_STATE;
					}
					else if(gapRole_ConnectState[pkt->connectionHandle] == GAPROLE_SLAVE_CONNECTED_STATE)
					{
						gapRole_ConnectState[pkt->connectionHandle] = GAPROLE_SLAVE_DISCONNECTED_STATE;
					}
					else
					{
						gapRole_ConnectState[pkt->connectionHandle] = GAPROLE_IDLE_STATE;
					}
				}
			}
			LOG("disconnected reason[%d]!\n", pkt->reason);

        #if (DEFAULT_GAPBOND_MGR_ENABLE==1)
			VOID GAPBondMgr_ProcessGAPMsg((gapEventHdr_t *)pMsg);
        #endif
			VOID osal_stop_timerEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT);
//			notify = TRUE;
		}
		break;

		// Security request received from slave
		case GAP_SLAVE_REQUESTED_SECURITY_EVENT:
		{
//      uint16_t connHandle = ((gapSlaveSecurityReqEvent_t *)pMsg)->connectionHandle;
//      uint8_t authReq = ((gapSlaveSecurityReqEvent_t *)pMsg)->authReq;

//      // Start security initialization
//      GAPBondMgr_SlaveReqSecurity(connHandle, authReq);
        #if (DEFAULT_GAPBOND_MGR_ENABLE==1)
			VOID GAPBondMgr_ProcessGAPMsg(pMsg);
        #endif
		}
		break;

		// Connection parameter update
		case GAP_LINK_PARAM_UPDATE_EVENT:
		{
			gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg;

//      // Cancel connection param update timeout timer (if active)
			VOID osal_stop_timerEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT);


			if(pPkt->hdr.status == SUCCESS)
			{
				LOG("handle %d,Intv %d,latency %d,Timeout %d\n",    pPkt->connectionHandle,\
				    pPkt->connInterval,\
				    pPkt->connLatency,\
				    pPkt->connTimeout);
			}
		}
		break;

		case GAP_DEVICE_DISCOVERY_EVENT:
			gapRole_ScanState = GAPROLE_SCAN_OFF_STATE;
			break;

		// TODO: new message, how to process it???
//  case GAP_UPDATE_LINK_PARAM_REQ_EVENT:
//    {
//      gapUpdateLinkParamReqEvent_t *pReq;
//      gapUpdateLinkParamReqReply_t rsp;

//      pReq = (gapUpdateLinkParamReqEvent_t *)pMsg;

//      // Add in connection handle.
//      rsp.connectionHandle = pReq->req.connectionHandle;

//      // If forwarding to the application to decide
//      if(gapRole_updateConnParams.paramUpdateEnable ==
//         GAPROLE_LINK_PARAM_UPDATE_APP_DECIDES)
//      {
//        if (pGapRoles_AppCGs && pGapRoles_AppCGs->pfnParamUpdateAppDecision)
//        {
//          // Call application callback
//          pGapRoles_AppCGs->pfnParamUpdateAppDecision(&(pReq->req), &rsp);
//        }

//        // Reject if there is no registered callback
//        else
//        {
//          rsp.accepted = FALSE;
//        }
//      }

//      // If rejecting all parameter update requests
//      else if (gapRole_updateConnParams.paramUpdateEnable ==
//               GAPROLE_LINK_PARAM_UPDATE_REJECT)
//      {
//        rsp.accepted = FALSE;
//      }

//      // If accepting all parameter update rqeuests
//      else if (gapRole_updateConnParams.paramUpdateEnable ==
//               GAPROLE_LINK_PARAM_UPDATE_ACCEPT)
//      {
//        // Link Parameter update is accepted
//        rsp.accepted = TRUE;

//        // Use remote requested values
//        rsp.intervalMin = pReq->req.intervalMin;
//        rsp.intervalMax = pReq->req.intervalMax;
//        rsp.connLatency = pReq->req.connLatency;
//        rsp.connTimeout = pReq->req.connTimeout;
//      }

//      // Send parameters back to stack
//      VOID GAP_UpdateLinkParamReqReply(&rsp);
//    }
//  break;
		default:
//			notify = TRUE;
			break;
	}

	// Pass event to app
	if(pGapRoles_AppCGs && pGapRoles_AppCGs->eventCB)
	{
		pGapRoles_AppCGs->eventCB((gapCentralRoleEvent_t *) pMsg);
	}

//  if (notify == TRUE) // App needs to take further action
//  {
//    if (pGapRoles_AppCGs && pGapRoles_AppCGs->pfnPassThrough)
//    {
//      // Call application callback
//      return (pGapRoles_AppCGs->pfnPassThrough((gapMultiRoleEvent_t *)pMsg));
//    }
//  }

	return TRUE;
}

/*********************************************************************
* @fn      gapRole_HandleParamUpdateNoSuccess
*
* @brief   Handle unsuccessful connection parameters update.
*
* @param   none
*
* @return  none
*/
static void gapRole_HandleParamUpdateNoSuccess(void)
{
	// See which option was chosen for unsuccessful updates
	switch(paramUpdateNoSuccessOption)
	{
		// Attempt to send the connection parameter update again
		case GAPROLE_RESEND_PARAM_UPDATE:
//    gapRole_connUpdate(GAPROLE_RESEND_PARAM_UPDATE, &gapRole_updateConnParams);
			GAPMultiRole_SendUpdateParam(gapRole_updateConnParams.minConnInterval,
			                             gapRole_updateConnParams.maxConnInterval,
			                             gapRole_updateConnParams.slaveLatency,
			                             gapRole_updateConnParams.timeoutMultiplier,
			                             GAPROLE_RESEND_PARAM_UPDATE);
			break;

		// Drop the connection
		case GAPROLE_TERMINATE_LINK:
			GAPMultiRole_TerminateConnection(gapRole_updateConnParams.connHandle);
			break;

		// Give up and proceed
		case GAPROLE_NO_ACTION:

		// Fall through
		default:
			// Do nothing
			break;
	}
}

/*********************************************************************
* @fn      gapRole_SetupGAP
*
* @brief   Call the GAP Device Initialization function using the
*          Profile Parameters. Negotiate the maximum number
*          of simultaneous connections with the stack.
*
* @param   numConns - desired number of simultaneous connections
*
* @return  none
*/
static void gapRole_SetupGAP(uint8_t * numConns)
{
	// Set number of possible simultaneous connections
	*numConns = linkDBNumConns;

	VOID GAP_DeviceInit(gapRole_TaskID, gapRole_profileRole, gapRoleMaxScanRes,
	                    gapRole_IRK, gapRole_SRK,
	                    (uint32*)&gapRole_signCounter);
}

/*********************************************************************
* @fn      gapRole_setEvent
*
* @brief   Set an event
*
* @param   event - event to be set
*
* @return  none
*/
//static void gapRole_setEvent(uint32_t event)
void gapRole_setEvent(uint32_t event)
{
	// Wake up the application thread when it waits for clock event
//  Event_post(syncEvent, event);
	osal_set_event(gapRole_TaskID, event);
}

/********************************************************************
 * @fn          GAPRole_SendUpdateParam
 *
 * @brief       Update the parameters of an existing connection
 *
 * @param       minConnInterval - the new min connection interval
 * @param       maxConnInterval - the new max connection interval
 * @param       latency - the new slave latency
 * @param       connTimeout - the new timeout value
 * @param       handleFailure - what to do if the update does not occur.
 *              Method may choose to terminate connection, try again, or take no action
 *
 * @return      SUCCESS, bleNotConnected, or bleInvalidRange
 */
bStatus_t GAPMultiRole_SendUpdateParam(uint16 minConnInterval, uint16 maxConnInterval,
                                       uint16 latency, uint16 connTimeout, uint8 handleFailure)
{
	return SUCCESS;
}


static void MultiRole_startConnUpdate(uint8 handleFailure)
{
	// First check the current connection parameters versus the configured parameters

	l2capParamUpdateReq_t updateReq;
	uint16 timeout = GAP_GetParamValue(TGAP_CONN_PARAM_TIMEOUT);

	updateReq.intervalMin = connin_table[user_data.connin];
	updateReq.intervalMax = connin_table[user_data.connin];
	updateReq.slaveLatency = 0;
	updateReq.timeoutMultiplier = 500;
	//LOG("updateReq.intervalMin %d MAX_NUM_LL_CONN %d\n",updateReq.intervalMin,MAX_NUM_LL_CONN);
	//LOG("osal_get_timeoutEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT) %d \n",osal_get_timeoutEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT));
	//if(osal_get_timeoutEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT) == 0)
	{
		
		for(uint16 i =0; i< MAX_MASTER_NUM; i++)
		{

			//if(multi_updateParamList[i])
			{	
				//multi_updateParamList[i] = FALSE;
				L2CAP_ConnParamUpdateReq(masterDevInfo[i].ConnectionHandle, &updateReq, gapRole_TaskID);
				
				paramUpdateNoSuccessOption = handleFailure;

				//osal_start_timerEx(gapRole_TaskID, START_CONN_UPDATE_EVT, 6000);

				// Let's wait for L2CAP Connection Parameters Update Response
				osal_start_timerEx(gapRole_TaskID, CONN_PARAM_TIMEOUT_EVT, timeout);

				//break;
			}
		}
	}
	//else
	{
		//osal_start_timerEx(gapRole_TaskID, START_CONN_UPDATE_EVT, 6000);
	}
}

/*********************************************************************
* @fn      	bStatus_t MultiRole_EncodeAdvDeviceAddr(uint8_t * pAdvData, uint16_t * pOffset, uint16_t maxSize)
* @brief    Encode advdata about device address
* @param    pAdvData - advdata buffer
*			pOffset - encode data offset in advdata buffer
*			maxSize - maximum size for advdata buffer
* @return   none.
*/
bStatus_t MultiRole_EncodeAdvDeviceAddr(uint8_t * pAdvData, uint8_t * pOffset, uint8_t maxSize)
{
	//uint8_t *devAddr;
	uint8_t devAddr[6];
	uint8_t temp_devAddr[6];
	uint8_t offset;
	offset = *pOffset;
	if(offset + 3 + LL_DEVICE_ADDR_LEN > maxSize)
	{
		return bleInvalidRange;
	}
    //devAddr = gapGetDevAddress( FALSE );
	LL_ReadBDADDR(devAddr);
	for (int i=0, j=5; j>=0; ++i, --j)
    {
        temp_devAddr[i] = devAddr[j];
    }
	pAdvData[offset++] = 1+LL_DEVICE_ADDR_LEN;
	pAdvData[offset++] = GAP_ADTYPE_LE_BLUETOOTH_DEVICE_ADDRESS;
	//pAdvData[offset++] = ADDRTYPE_PUBLIC ;
	osal_memcpy(&pAdvData[offset], temp_devAddr, LL_DEVICE_ADDR_LEN);
	offset+=LL_DEVICE_ADDR_LEN;
	*pOffset = offset;
	return SUCCESS;
}

/*********************************************************************
* @fn      	bStatus_t MultiRole_EncodeAdvDeviceName(uint8_t * pAdvData, uint8_t * pOffset, uint8_t maxSize, uint8_t *devName, uint8_t devNameLen)
* @brief    Encode advdata about device name
* @param    pAdvData - advdata buffer
*			pOffset - encode data offset in advdata buffer
*			maxSize - maximum size for advdata buffer
* 			devName - device name
*			devNameLen - device name length
* @return   none.
*/
bStatus_t MultiRole_EncodeAdvDeviceName(uint8_t * pAdvData, uint8_t * pOffset, uint8_t maxSize, uint8_t *devName, uint8_t devNameLen)
{
	uint8_t offset;
	offset = *pOffset;
	if(offset + 2 + devNameLen > maxSize)
	{
		return bleInvalidRange;
	}
	pAdvData[offset++] = 1+devNameLen;
	pAdvData[offset++] = GAP_ADTYPE_LOCAL_NAME_COMPLETE;
	osal_memcpy(&pAdvData[offset], devName, devNameLen);
	offset += devNameLen;
	*pOffset = offset;
	
	return SUCCESS;
}
